package com.hongji.lms5xxcommunicator.realtime;

import com.hongji.lms5xxcommunicator.entity.SnapshotCache;
import com.hongji.lms5xxcommunicator.entity.ScanPointEntity;
import com.hongji.lms5xxcommunicator.grid.export.GridDeltaPayload;
import com.hongji.lms5xxcommunicator.grid.export.GridPoint;
import com.hongji.lms5xxcommunicator.realtime.websoket.SpringWsBroadcaster;
import com.hongji.lms5xxcommunicator.grid.RasterGrid;
import com.hongji.lms5xxcommunicator.grid.core.GridSpec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
public class WsTransferService {

    private final SpringWsBroadcaster wsBroadcaster;
    private final SnapshotCache snapshotCache;
    private final PointDtoMapper mapper;
    private final int wsBatchSize;

    /** 帧号（每次 pushPoints 视为一整帧，递增编号） */
    private static final AtomicLong SEQ = new AtomicLong(0L);

    public WsTransferService(SpringWsBroadcaster wsBroadcaster,
                             SnapshotCache snapshotCache,
                             PointDtoMapper mapper,
                             int wsBatchSize) {
        this.wsBroadcaster = wsBroadcaster;
        this.snapshotCache = snapshotCache;
        this.mapper = mapper;
        this.wsBatchSize = Math.max(1, wsBatchSize);
    }

    /**
     * 推送“栅格增量”（rc 数组；每片携带 zMin/zMax/rangeSeq）
     */
    public void pushDelta(GridDeltaPayload payload, RasterGrid grid) {
        if (payload == null || grid == null) return;

        final List<GridPoint> ups = (payload.getUpdates() != null) ? payload.getUpdates() : java.util.Collections.emptyList();
        final GridSpec spec = grid.spec();
        final int chunkSize = wsBatchSize;
        final int n = ups.size();
        final int totalChunks = (n == 0) ? 1 : ((n + chunkSize - 1) / chunkSize);

        final long seq = SEQ.incrementAndGet();
        int chunks = 0;

        if (n == 0) {
            Map<String, Object> dto = mapper.cellsDeltaMessage(
                    new GridDeltaPayload(java.util.Collections.emptyList(), payload.getVolume(), payload.isFull()),
                    spec, grid
            );
            dto.put("seq", seq);
            dto.put("chunk", 1);
            dto.put("chunks", 1);
            wsBroadcaster.broadcast(dto);
            snapshotCache.update(dto);
            log.info("【WS】delta 推送：seq={} full={} cells=0 chunks=1/1 volume={}",
                    seq, payload.isFull(), String.format("%.2f", payload.getVolume()));
            return;
        }

        for (int i = 0; i < n; i += chunkSize) {
            final int idx = i / chunkSize;
            final boolean thisFull = (payload.isFull() && i == 0);
            final List<GridPoint> sub = ups.subList(i, Math.min(n, i + chunkSize));

            GridDeltaPayload subPayload = new GridDeltaPayload(sub, payload.getVolume(), thisFull);
            Map<String, Object> dto = mapper.cellsDeltaMessage(subPayload, spec, grid);

            dto.put("seq", seq);
            dto.put("chunk", idx + 1);
            dto.put("chunks", totalChunks);

            wsBroadcaster.broadcast(dto);
            snapshotCache.update(dto);
            chunks++;
        }

        log.info("【WS】delta 推送：seq={} full={} cells={} chunks={}/{} volume={}",
                seq, payload.isFull(), n, chunks, totalChunks, String.format("%.2f", payload.getVolume()));
    }

    public void pushDto(Object dto) {
        if (dto == null) return;
        wsBroadcaster.broadcast(dto);
        snapshotCache.update(dto);
        log.info("【WS】已推送现成 DTO");
    }
}
